package cn.hg.solon.youcan.web.admin.controller.system;

import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.convert.Convert;
import org.dromara.hutool.core.text.StrValidator;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.MethodType;
import org.noear.solon.core.handle.ModelAndView;
import org.noear.solon.core.handle.Result;
import org.noear.solon.data.annotation.Cache;
import org.noear.solon.data.annotation.CacheRemove;
import org.noear.solon.validation.annotation.NotBlank;
import org.noear.solon.validation.annotation.NotEmpty;
import org.noear.solon.validation.annotation.NotNull;

import com.mybatisflex.core.paginate.Page;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hg.solon.youcan.common.annotation.Log;
import cn.hg.solon.youcan.common.constant.CacheConstants;
import cn.hg.solon.youcan.common.enums.BusinessType;
import cn.hg.solon.youcan.common.web.LayuiPage;
import cn.hg.solon.youcan.framework.satoken.SaUtil;
import cn.hg.solon.youcan.system.entity.SysUser;
import cn.hg.solon.youcan.system.service.SysRoleService;
import cn.hg.solon.youcan.system.service.SysUserService;
import cn.hg.solon.youcan.web.admin.controller.BaseAdminController;
import cn.hg.solon.youcan.web.admin.controller.system.qo.UserQueryObject;

/**
 * @author 胡高
 */
@Controller
@Mapping("/admin/system/user")
public class UserController extends BaseAdminController {

    private static final String SERVICE_NAME = "系统用户";

    private static final String VIEW_PATH = "/admin/system/user/";

    @Inject
    SysUserService userService;

    @Inject
    SysRoleService roleService;

    /**
     * 跳转到新增页面
     */
    @Mapping(path = "add", method = MethodType.GET)
    @SaCheckLogin
    public ModelAndView add(Context ctx) {
        this.log.info("跳转到新增[{}]页面", SERVICE_NAME);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "add.html");

        this.preEdit(mav, null);

        return mav;
    }

    @Mapping(path = "addSave", method = MethodType.POST)
    @Log(title = SERVICE_NAME, businessType = BusinessType.CREATE)
    @SaCheckPermission(value = {"system:user:add"})
    @CacheRemove(tags = CacheConstants.SYS_USER_TAG)
    public Result<?> addSave(Context ctx, @NotNull SysUser bean, String roleIds) {
        this.log.info("新增[{}]记录：bean={}", SERVICE_NAME, bean);

        // 初始化数据
        bean.setSalt(RandomUtil.randomString(20));
        bean.setType("SYSTEM"); // 凡是在管理页面中注册的用户都为System

        this.userService.save(bean);

        this.userService.assignRole(bean,
            StrValidator.isBlank(roleIds) ? new Integer[0] : Convert.toIntArray(SplitUtil.split(roleIds, ",")));

        return Result.succeed();
    }

    @Mapping(path = "assignRole", method = MethodType.GET)
    @SaCheckLogin
    @CacheRemove(tags = CacheConstants.SYS_USER_TAG)
    public ModelAndView assignRole(Context ctx, @NotNull Integer id) {
        this.log.info("跳转到[{}]分配角色页面：id={}", SERVICE_NAME, id);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "assignRole.html");

        this.preEdit(mav, id);

        return mav;

    }

    @Mapping(path = "delete", method = MethodType.DELETE)
    @Log(title = SERVICE_NAME, businessType = BusinessType.DELETE)
    @SaCheckPermission(value = {"system:user:del"})
    @CacheRemove(tags = CacheConstants.SYS_DICT_TAG)
    public Result<?> delete(Context ctx, @NotBlank String ids) {
        this.log.info("删除[{}]记录：ids={}", SERVICE_NAME, ids);

        return this.roleService.removeByIds(StrValidator.isBlank(ids) ? ListUtil.empty() : SplitUtil.split(ids, ","))
            ? Result.succeed()
                : Result.failure();
    }

    @Mapping(path = "doAssignRole", method = MethodType.PUT)
    @Log(title = "分配角色", businessType = BusinessType.GRANT)
    @SaCheckPermission(value = {"system:user:assignRole"})
    @CacheRemove(tags = CacheConstants.SYS_USER_TAG + "," + CacheConstants.SYS_CONFIG_TAG)
    public Result<?> doAssignRole(Context ctx, @NotNull Integer id, String roleIds) {
        this.log.info("执行[{}]分配角色操作：id={}, roleIds={}", SERVICE_NAME, id, roleIds);

        this.userService.assignRole(this.userService.getById(id),
            StrValidator.isBlank(roleIds) ? new Integer[0] : Convert.toIntArray(SplitUtil.split(roleIds, ",")));

        return Result.succeed();
    }

    @Mapping(path = "doResetPassword", method = MethodType.PUT)
    @Log(title = "重置密码", businessType = BusinessType.UPDATE)
    @SaCheckPermission(value = {"system:user:edit"})
    public Result<?> doResetPassword(Context ctx, @NotNull Integer id,
        @NotEmpty
        // @Size(min = 6, max = 20, message = "重置密码长度必须 6 到 20 字符")
        String password) {
        this.log.info("执行[{}]重置密码操作：id={}", SERVICE_NAME, id);

        this.userService.resetPassword(this.userService.getById(id), password, SaUtil.getCurrentUser());

        return Result.succeed();
    }

    /**
     * 跳转到编辑页面
     */
    @Mapping(path = "edit", method = MethodType.GET)
    @SaCheckLogin
    public ModelAndView edit(Context ctx, int id) {
        this.log.info("跳转到编辑[{}]页面", SERVICE_NAME);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "edit.html");

        this.preEdit(mav, id);

        return mav;
    }

    @Mapping(path = "editSave", method = MethodType.PUT)
    @Log(title = SERVICE_NAME, businessType = BusinessType.UPDATE)
    @SaCheckPermission(value = {"system:user:edit"})
    @CacheRemove(tags = CacheConstants.SYS_USER_TAG)
    public Result<?> editSave(Context ctx, @NotNull SysUser bean, String roleIds) {
        this.log.info("更新[{}]记录：bean={}", SERVICE_NAME, bean);

        // 更新到数据库
        this.userService.update(bean);

        this.userService.assignRole(bean,
            StrValidator.isBlank(roleIds) ? new Integer[0] : Convert.toIntArray(SplitUtil.split(roleIds, ",")));

        return Result.succeed();
    }

    @Mapping(path = "", method = MethodType.GET)
    @SaCheckLogin
    public ModelAndView index(Context ctx) {
        this.log.info("跳转到[{}]列表页面", SERVICE_NAME);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "index.html");

        // 如果打开列表页面时有参数传递过来，则继续
        mav.putAll(ctx.paramMap());

        return mav;
    }

    private void preEdit(ModelAndView mav, Integer id) {
        SysUser user = ObjUtil.isNull(id) ? new SysUser() : this.userService.getById(id);

        mav.put("bean", user);
    }

    /**
     * 分页查询功能
     */
    @Mapping(path = "query", method = MethodType.POST)
    @SaCheckPermission(value = {"system:user:query"})
    @Cache(key="query:${query}", tags = CacheConstants.SYS_USER_TAG , seconds = CacheConstants.CACHE_SECONDS_ONE_HOUR)
    public LayuiPage<SysUser> query(Context ctx, @NotNull UserQueryObject query) {
        this.log.info("执行[{}]分页查询：query={}", SERVICE_NAME, query);

        /*
         * 服务调用
         */
        Page<SysUser> result =
            this.userService.pageByMap(new Page<>(query.getPageNumber(), query.getPageSize()), query.toMap());

        /*
         * 返回值处理
         */
        return new LayuiPage<>(result.getRecords(), result.getTotalRow());
    }

    @Mapping(path = "resetPassword", method = MethodType.GET)
    @SaCheckLogin
    public ModelAndView resetPassword(Context ctx, @NotNull Integer id) {
        this.log.info("跳转到[{}]重置密码页面：id={}", SERVICE_NAME, id);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "resetPassword.html");

        mav.put("bean", this.userService.getById(id));

        return mav;
    }

    /**
     * 跳转到记录展示页面
     */
    @Mapping(path = "view", method = MethodType.GET)
    @SaCheckPermission(value = {"system:user:query"})
    public ModelAndView view(Context ctx, int id) {
        this.log.info("跳转到[{}]展示页面：id={}", SERVICE_NAME, id);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "view.html");

        mav.put("bean", this.userService.getById(id));

        return mav;
    }
}
